package net.zoneland.zrdp.common.utils.html;


import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeFactory;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.ObjectNode;



/**
 * 转义和反转义工具类
 *
 * @author zonevue
 */
public class EscapeUtil
{
    private EscapeUtil() {
        throw new IllegalStateException("Utility class");
    }


    /**
     * 过滤用户输入的HTML内容，去除所有html标签。注意：会把用户输入的 &amp;lt; 等转义成<; (如 a &amp;lt; b 最后结果变成 a < b)
     * <p>Example:</p>
     * <pre>{@code
     *     String sourceBodyHtml = "<p>5 is &lt; 6.</p>";
     *     String html = EscapeUtil.cleanXss(sourceBodyHtml);
     *
     *     String sourceBodyHtml1 = "<script>5 is &lt; 6.</script>";
     *     String html1 = EscapeUtil.cleanXss(sourceBodyHtml1);
     *
     *     String sourceBodyHtml2 = "{\"name\":\"张三<script>alert('XSS attack')\",\"age\":18}";
     *     String html2 = EscapeUtil.cleanXss(sourceBodyHtml2);
     *
     *     // html is: "5 is < 6."
     *     // html1 is: ""
     *     // html2 is: "｛\"name\":\"张三"
     * }</pre>
     *
     * @param content 文本
     * @return 清除标签后的文本
     */
    public static String cleanXss(final String content) {
        return HtmlXssFilter.filter(content);
    }

    /**
     * 清除Json数据中的Xss过滤策略相关的内容
     * @param node jsonnode
     * @param mapper jsonmapper
     * @return 清除后的jsonnode
     */
    public static JsonNode jsonCleanXss(final JsonNode node, final ObjectMapper mapper) {
        if(node.isValueNode()) { // Base case - we have a Number, Boolean or String
            if(JsonNodeType.STRING == node.getNodeType()) {
                // 对 String values 进行过滤
                return JsonNodeFactory.instance.textNode(HtmlXssFilter.filter(node.asText()));
            } else {
                return node;
            }
        } else if(node.isArray()) { // If the object is an array  "cars": ["toyota", "nissan", "bmw"]
            final ArrayNode cleanedArray = mapper.createArrayNode();
            node.forEach(objNode -> cleanedArray.add(jsonCleanXss(objNode, mapper)));
            return cleanedArray;
        } else { // Recursive case - iterate over JSON object entries
            final ObjectNode sanitizedJsonNode = JsonNodeFactory.instance.objectNode();
            node.fields().forEachRemaining(entry ->
                sanitizedJsonNode.set(entry.getKey(), jsonCleanXss(entry.getValue(), mapper))
            );
            return sanitizedJsonNode;
        }
    }

}
